/* !
 * @Author: miss-tree
 * @Date: 2022-01-07 09:47:01
 * @Description: 学习 vue-router
*/

/**
 * 将路由参数返回一个对象
 * @param {*} query  路由url
 * @returns 返回路由传参对象
 */
function parseQuery (query) {
  var res = {};

  query = query.trim().replace(/^(\?|#|&)/, '');

  if (!query) {
    return res
  }

  query.split('&').forEach(function (param) {
    var parts = param.replace(/\+/g, ' ').split('=');
    var key = decode(parts.shift());
    var val = parts.length > 0 ? decode(parts.join('=')) : null;

    if (res[key] === undefined) {
      res[key] = val;
    } else if (Array.isArray(res[key])) {
      res[key].push(val);
    } else {
      res[key] = [res[key], val];
    }
  });

  return res
}

/**
 * 将一个对象转码编译不显示明参
 * @param {*} obj 需要传参的对象
 * @returns 
 */
function stringifyQuery (obj) {
  var res = obj
    ? Object.keys(obj)
      .map(function (key) {
        var val = obj[key];

        if (val === undefined) {
          return ''
        }

        if (val === null) {
          return encode(key)
        }

        if (Array.isArray(val)) {
          var result = [];
          val.forEach(function (val2) {
            if (val2 === undefined) {
              return
            }
            if (val2 === null) {
              result.push(encode(key));
            } else {
              result.push(encode(key) + '=' + encode(val2));
            }
          });
          return result.join('&')
        }

        return encode(key) + '=' + encode(val)
      })
      .filter(function (x) { return x.length > 0; })
      .join('&')
    : null;
  return res ? ("?" + res) : ''
}

/**
 * 简单拷贝方法
 * @param {*} value 拷贝对象
 * @returns 
 */
function clone (value) {
  if (Array.isArray(value)) {
    return value.map(clone)
  } else if (value && typeof value === 'object') {
    var res = {};
    for (var key in value) {
      res[key] = clone(value[key]);
    }
    return res
  } else {
    return value
  }
}

/**
 * 对比两个对象是否相等
 * @param {*} a 
 * @param {*} b 
 * @returns 
 */
function isObjectEqual (a, b) {
  if (a === void 0) a = {};
  if (b === void 0) b = {};

  if (!a || !b) { return a === b }
  var aKeys = Object.keys(a).sort();
  var bKeys = Object.keys(b).sort();
  if (aKeys.length !== bKeys.length) {
    return false
  }
  return aKeys.every(function (key, i) {
    var aVal = a[key];
    var bKey = bKeys[i];
    if (bKey !== key) { return false }
    var bVal = b[key];
    // query values can be null and undefined
    if (aVal == null || bVal == null) { return aVal === bVal }
    // check nested equality
    if (typeof aVal === 'object' && typeof bVal === 'object') {
      return isObjectEqual(aVal, bVal)
    }
    return String(aVal) === String(bVal)
  })
}

/**
 * 函数只执行一次 
 * @param {*} fn 
 * @returns 
 */
function once (fn) {
  var called = false;
  return function () {
    var args = [], len = arguments.length;
    while (len--) args[len] = arguments[len];

    if (called) { return }
    called = true;
    return fn.apply(this, args)
  }
}

/**
 * History 模式获取记录栈方式
 * @param {*} current 
 * @param {*} next 
 * @returns 
 */
function resolveQueue (current, next) {
  var i;
  var max = Math.max(current.length, next.length);
  for (i = 0; i < max; i++) {
    if (current[i] !== next[i]) {
      break
    }
  }
  return {
    updated: next.slice(0, i),
    activated: next.slice(i),
    deactivated: current.slice(i)
  }
}

/**
 * 解决路由深度嵌套问题
 * @param {*} matched 
 * @param {*} fn 
 * @returns 
 */
function flatMapComponents ( matched, fn) {
  return flatten(matched.map(function (m) {
    return Object.keys(m.components).map(function (key) {
      return fn(
        m.components[key],
        m.instances[key],
        m, key
      );
    })
  }))
}

function flatten (arr) {
  return Array.prototype.concat.apply([], arr)
}